// 实现这个项目的构建任务
const { src, dest, series, parallel, watch } = require("gulp");
// 引入处理sass文件的插件
// const sass = require("gulp-sass");
// 用来处理模版的插件，将模版的通配符用变量进行替换
const swig = require("gulp-swig");
// 处理js的插件，需要引入 @babel/core 和 @babel/preset-env 将最新的ES6代码转换成低版本可兼容的代码
const babel = require("gulp-babel");
// js 代码压缩的插件
const uglify = require("gulp-uglify");
// 进行图片的压缩的插件
const imagemin = require("gulp-imagemin");
// 删除文件夹或文件的插件
const del = require("del");
// 用来启动一个服务器，实现热更新
const browserSync = require("browser-sync");
// 用来将index中的一些指向node_module的资源打包到dist目录下
const _if = require("gulp-if");
// 压缩html
const htmlmin = require("gulp-htmlmin");
// 压缩css
const cleanCss = require("gulp-clean-css");
// 修改hmtl引用文件指向
const useref = require("gulp-useref");

// 创建一个服务器
const bs = browserSync.create();

const data = {
  menus: [
    {
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    {
      name: "Features",
      link: "features.html",
    },
    {
      name: "About",
      link: "about.html",
    },
    {
      name: "Contact",
      link: "#",
      children: [
        {
          name: "Twitter",
          link: "https://twitter.com/w_zce",
        },
        {
          name: "About",
          link: "https://weibo.com/zceme",
        },
        {
          name: "divider",
        },
        {
          name: "About",
          link: "https://github.com/zce",
        },
      ],
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

// 清理构建的文件夹
const clean = () => {
  return del(["dist"]);
};

// 构建css
const style = () => {
  // 设置base保留后面的路径到dist文件夹
  return (
    src("src/assets/styles/*.scss", { base: "src" })
      .pipe(sass())
      .pipe(dest("dist"))
  );
};

// 构建js
const script = () => {
  // 设置base保留后面的路径到dist文件夹
  return src("src/assets/scripts/*.js", { base: "src" })
    .pipe(babel({ presets: ["@babel/preset-env"] }))
    .pipe(uglify())
    .pipe(dest("dist"));
};

// 构建html
const page = () => {
  return (
    src("src/*.html", { base: "src" })
      // 防止模板缓存导致页面不能及时更新
      .pipe(swig({ data, defaults: { cache: false } }))
      .pipe(dest("dist"))
  );
};

// 构建图片
const image = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(imagemin())
    .pipe(dest("dist"));
};

// 构建字体文件
const font = () => {
  return src("src/assets/fonts/**", { base: "src" })
    .pipe(imagemin())
    .pipe(dest("dist"));
};

// 打包public里面的东西
const extra = () => {
  // 这里保留了public的路径
  return src("public/**", { base: "public" }).pipe(dest("dist"));
};

const serve = () => {
  // 监听不同类型的文件改动，自动执行打包动作，确保dist文件夹中的代码是最新的
  watch("src/assets/styles/*.scss", style);
  watch("src/assets/scripts/*.js", script);
  watch("src/*.html", page);
  // 图片改动的时候，需要利用 bs.reload 重新刷新浏览器
  // 这里和上面的不一样主要是因为图片压缩和不压缩差别不大，不进行构建可以为本地开发节省更多的资源
  watch(
    ["src/assets/images/**", "src/assets/fonts/**", "public/**"],
    bs.reload
  );

  bs.init({
    notify: false,
    // open: false,
    files: 'dist/**', // files路径的作用是监听路径下的变化，有变动就自动刷新
    server: {
      // 指定三个目录，当请求来了之后会依次到所设置的文件夹中去找
      // 设置三个目录的原因是因为开发阶段不需要频繁的编译压缩图片，意义不大，直接加载本地的图片即可，节省构建压缩的资源，如果本地图片有改动，就直接自动刷新浏览器即可
      baseDir: ['dist', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
};

// 这里的changRef 依赖的文件是compile生成的，所以需要通过series和 compile进行串行执行
const changeRef = () => {
  // 获取dist目录下的html 分析其中需要转换的文件
  return (
    src("dist/*.html", { base: "dist" })
      // 在dist 和 根目录下去寻找html中依赖的文件并且打包
      .pipe(useref({ searchPath: ["dist", "."] }))
      // html 中依赖的文件可能有三种 html css js，所以需要分别打包
      // 利用 gulp-if 模块进行文件流的判断进行分别压缩
      .pipe(_if(/\.js$/, uglify()))
      .pipe(_if(/\.css$/, cleanCss()))
      .pipe(_if(/\.html$/, htmlmin()))
      .pipe(dest("dist"))
  );
};

const compile = parallel(style, script, page);
const assets = parallel(image, font, extra);

// 上线之前执行的任务
const build = series(clean, parallel(series(compile, changeRef), assets));
// 开启服务器
const develop = series(compile, serve);

module.exports = {
  clean,
  build,
  develop,
};
